package wsi.match;

import java.util.Map;
import java.util.Map.Entry;

import org.rygh.core.html.Html;
import org.rygh.core.html.element.HtmlImg;
import org.rygh.core.html.table.HtmlTable;
import org.rygh.core.html.table.TableData;
import org.rygh.core.html.table.TableTuple;
import org.rygh.core.model.common.MapList;
import org.rygh.core.util.UMath;
import org.rygh.core.util.counter.ProbabilitySpanner;
import org.rygh.core.util.counter.SimpleCounter;
import org.rygh.semantic.gui.swing.input.Input;

import wsi.dataguide.tree.WSXmlLeaf;

public class SubtreeCounter {

	private final SimpleCounter<String> subMatchFrequency = new SimpleCounter<>();
	private final SimpleCounter<String> supMatchFrequency = new SimpleCounter<>();
	private final SimpleCounter<WSXmlLeaf> unmatchedCounter = new SimpleCounter<>();
	private final SimpleCounter<WSXmlLeaf> unmatchedSupCounter = new SimpleCounter<>();

	private final SimpleCounter<Integer> matchCountFrequency = new SimpleCounter<>();
	private final ProbabilitySpanner positiveProbFrequency = new ProbabilitySpanner(
			20);

	private final int length = 7;
	private final double[][] max = new double[2][length];
	private final double[][] min = new double[2][length];
	private final double[][] avg = new double[2][length];
	private final double[][] deviations = new double[2][length];

	protected final Input[] inputs;
	private Map<WSXmlLeaf, SubtreeMatch> matchMap;

	public SubtreeCounter(Input[] inputs) {
		this.inputs = inputs;
	}

	public void computeStatistics(Map<Input, SubtreeMatch> supnodeMap,
			int subrootCount) {
		/* statistics for all subtrees */

		int i = 0, c = length;
		double[][] supnumbers = new double[c][supnodeMap.size()];
		double[][] subnumbers = new double[c][matchMap.size()];

		for (SubtreeMatch sm : supnodeMap.values()) {
			for (MatchPair pair : sm.getMatchPairs())
				supMatchFrequency.count(pair.getKey());

			supnumbers[0][i] = sm.getCountMatchedLeaves();
			supnumbers[1][i] = sm.getSumCompInvFunc();
			supnumbers[2][i] = sm.getSumProdCompInvFuncAndInvFunc();
			supnumbers[3][i] = sm.getAvgCompInvFunc();
			supnumbers[4][i] = sm.getAvgProdCompInvFuncAndInvFunc();
			supnumbers[5][i] = sm.getProbPositiveValidMatch();
			supnumbers[6][i] = sm.getProbNegativeValidMatch();
			i++;
		}

		i = 0;
		for (SubtreeMatch sm : matchMap.values()) {

			for (MatchPair pair : sm.getMatchPairs())
				subMatchFrequency.count(pair.getKey());

			matchCountFrequency.count(sm.getCountMatchedLeaves());
			positiveProbFrequency
					.count((int) (sm.getProbPositiveValidMatch() * 100));

			subnumbers[0][i] = sm.getCountMatchedLeaves();
			subnumbers[1][i] = sm.getSumCompInvFunc();
			subnumbers[2][i] = sm.getSumProdCompInvFuncAndInvFunc();
			subnumbers[3][i] = sm.getAvgCompInvFunc();
			subnumbers[4][i] = sm.getAvgProdCompInvFuncAndInvFunc();
			subnumbers[5][i] = sm.getProbPositiveValidMatch();
			subnumbers[6][i] = sm.getProbNegativeValidMatch();
			i++;
		}

		supMatchFrequency.setNormalizeFactor(supnodeMap.size());
		subMatchFrequency.setNormalizeFactor(subrootCount);
		matchCountFrequency.setNormalizeFactor(inputs.length);
		positiveProbFrequency.setNormalizeFactor(inputs.length);

		for (i = 0; i < c; i++) {
			max[0][i] = UMath.max(0., subnumbers[i]);
			min[0][i] = UMath.min(0., subnumbers[i]);
			avg[0][i] = UMath.getAverage(subnumbers[i]);
			deviations[0][i] = UMath.getDeviation(subnumbers[i]);

			max[1][i] = UMath.max(0., supnumbers[i]);
			min[1][i] = UMath.min(0., supnumbers[i]);
			avg[1][i] = UMath.getAverage(supnumbers[i]);
			deviations[1][i] = UMath.getDeviation(supnumbers[i]);
		}
	}

	public SimpleCounter<String> getSubMatchFrequency() {
		return subMatchFrequency;
	}

	public SimpleCounter<String> getSupMatchFrequency() {
		return supMatchFrequency;
	}

	public SimpleCounter<WSXmlLeaf> getUnmatchedCounter() {
		return unmatchedCounter;
	}

	public SimpleCounter<WSXmlLeaf> getUnmatchedSupCounter() {
		return unmatchedSupCounter;
	}

	public void setMatchMap(Map<WSXmlLeaf, SubtreeMatch> matchMap) {
		this.matchMap = matchMap;
	}

	public String toString(String title,
			MapList<Input, WSXmlLeaf> subrootMapList) {
		Html html = new Html(title);

		HtmlImg img = new HtmlImg("../../../yagodata/subtree_mapping.png");
		html.addElement(img);

		html.newline();

		subMatchFrequency.setName("Match Info for Subtrees");
		html.addElement(subMatchFrequency.toHtmlTable());
		html.newline();

		supMatchFrequency.setName("Match Info for Sup-nodes");
		html.addElement(supMatchFrequency.toHtmlTable());
		html.newline();

		//

		unmatchedCounter.setName("Counter for Unmatched Leaves");
		html.addElement(unmatchedCounter.toHtmlTable());
		html.newline();

		unmatchedSupCounter.setName("Counter for Unmatched Sup Nodes");
		html.addElement(unmatchedSupCounter.toHtmlTable());
		html.newline();

		//

		HtmlTable table;
		TableTuple tuple;
		TableData data;

		//

		data = new TableData();
		tuple = new TableTuple();
		tuple.add("Input", "Subtree Count");
		data.add(tuple);

		for (Input input : inputs) {
			tuple = new TableTuple();
			tuple.add(input.getValue());

			if (subrootMapList.containsKey(input))
				tuple.add(subrootMapList.get(input).size());
			else
				tuple.add("/");

			data.add(tuple);
		}

		//

		table = new HtmlTable("Overall Statistics for Subtrees", data, true);
		html.addElement(table);
		html.newline();

		//

		data = new TableData();
		tuple = new TableTuple();
		tuple.add("Item", "Max", "Min", "Average", "Deviation", "Frequency");
		data.add(tuple);

		String[] descriptions = {
				/**/"# of matches",
				/**/"&sum; <i>f<sub>T'</sub><sup>&ndash;1</sup>(p)</i>",
				/**/"&sum; <i>f<sub>T'</sub><sup>&ndash;1</sup>(p) &sdot; f<sup>&ndash;1</sup>(r)</i> ",
				/**/"Avg of <i>f<sub>T'</sub><sup>&ndash;1</sup>(p)</i>",
				/**/"Avg of <i>f<sub>T'</sub><sup>&ndash;1</sup>(p) &sdot; f<sup>&ndash;1</sup>(r)</i> ",
				/**/"<i>Pr(x &equiv; t)</i>",
				/**/"<i>Pr<sub>NEG</sub>(x &equiv; t)</i>", };

		for (int i = 0; i < descriptions.length; i++) {
			tuple = new TableTuple();
			tuple.add(descriptions[i]);
			tuple.add(String.format("%.5f", max[0][i]));
			tuple.add(String.format("%.5f", min[0][i]));
			tuple.add(String.format("%.5f", avg[0][i]));
			tuple.add(String.format("%.5f", deviations[0][i]));

			switch (i) {
			case 0:
				tuple.add(matchCountFrequency.toString());
				break;

			case 5:
				tuple.add(positiveProbFrequency.toString());
				break;

			default:
				tuple.add("");
			}

			data.add(tuple);
		}

		//

		table = new HtmlTable("Overall Statistics for Subtrees", data, true);
		html.addElement(table);
		html.newline();

		//

		data = new TableData();

		tuple = new TableTuple();
		tuple.add("Item", "Max", "Min", "Average", "Deviation", "Frequency");
		data.add(tuple);

		for (int i = 0; i < descriptions.length; i++) {
			tuple = new TableTuple();
			tuple.add(descriptions[i]);
			tuple.add(String.format("%.5f", max[1][i]));
			tuple.add(String.format("%.5f", min[1][i]));
			tuple.add(String.format("%.5f", avg[1][i]));
			tuple.add(String.format("%.5f", deviations[1][i]));

			tuple.add("");

			data.add(tuple);
		}

		//

		table = new HtmlTable("Overall Statistics for Sup-Nodes", data, true);
		html.addElement(table);
		html.newline();

		//

		data = new TableData();

		tuple = new TableTuple();
		tuple.add("Input");
		tuple.add(descriptions[0]);
		tuple.add("Subtree Root");

		for (int i = 1; i < descriptions.length; i++)
			tuple.add(descriptions[i]);

		data.add(tuple);

		for (Entry<WSXmlLeaf, SubtreeMatch> e : matchMap.entrySet()) {

			SubtreeMatch sm = e.getValue();

			tuple = new TableTuple();
			tuple.add(e.getKey().getValue().getValue());
			tuple.add("" + sm.getCountMatchedLeaves());
			tuple.add(sm.getSubroot().getXpath().getValue());
			tuple.add(String.format("%.5f", sm.getSumCompInvFunc()));
			tuple.add(String.format("%.5f",
					sm.getSumProdCompInvFuncAndInvFunc()));
			tuple.add(String.format("%.5f", sm.getAvgCompInvFunc()));
			tuple.add(String.format("%.5f",
					sm.getAvgProdCompInvFuncAndInvFunc()));
			tuple.add(String.format("%.5f", sm.getProbPositiveValidMatch()));
			tuple.add(String.format("%.5f", sm.getProbNegativeValidMatch()));
			data.add(tuple);
		}

		data.sort();
		table = new HtmlTable("Subtree Statistics", data, false);
		html.addElement(table);

		return html.toString();

	}
}
